// Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{fmt::Display, str::FromStr};

use serde::{Deserialize, Serialize};

use crate::{Version, VersionParseError};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
pub struct Pkg {
    pub name: String,
    pub version: Version,
}

#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum PkgParseError {
    #[error("bad pkg version")]
    BadVersion(#[from] VersionParseError),
    #[error("no pkg version")]
    NoVersion,
}

impl Display for Pkg {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}-{}", self.name, self.version)
    }
}

impl FromStr for Pkg {
    type Err = PkgParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.rsplit_once('-') {
            Some((name_str, version_str)) => {
                let version = Version::from_str(version_str)?;
                Ok(Self {
                    name: name_str.to_string(),
                    version,
                })
            },
            None => Err(PkgParseError::NoVersion)
        }
    }
}

impl Pkg {
    pub fn new(name: String, version: Version) -> Self {
        Self { name, version }
    }

    pub fn from_strings(name: String, version: String) -> Result<Self, VersionParseError> {
        Ok(Self {
            name,
            version: Version::try_from(version)?,
        })
    }
}

#[cfg(test)]
mod test {
    use std::str::FromStr;

    use crate::{Pkg, PkgParseError, Version};

    #[test]
    fn test_pkg_from_str() {
        assert_eq!(
            Pkg::from_str("test"),
            Err(PkgParseError::NoVersion)
        );
        assert_eq!(
            Pkg::from_str("test-1.2"),
            Ok(Pkg::new("test".to_string(),Version::from_major_minor(1,2)))
        );
    }
}